#include <stdlib.h>
#include "Arbre.h"
#include "Symbole.h"
#include "SymboleValue.h"

////////////////////////////////////////////////////////////////////////////////
// NoeudSeqInst
////////////////////////////////////////////////////////////////////////////////

NoeudSeqInst::NoeudSeqInst() : tabInst() {
}

////////////////////////////////////////////////////////////////////////////////
int NoeudSeqInst::getValeur() {
  int valeur=0;
  for (unsigned int i=0; i<tabInst.size(); i++)
    valeur = tabInst[i]->getValeur();  // on evalue chaque instruction de la séquence
  return valeur; // par convention, resultat = valeur de la derniere instruction
}

////////////////////////////////////////////////////////////////////////////////
void NoeudSeqInst::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Sequence de " << tabInst.size() << " instruction(s)" << endl;
  for (unsigned int i=0; i<tabInst.size(); i++)
    tabInst[i]->afficher(indentation+1); // on affiche les fils en augmentant l'indentation
}

////////////////////////////////////////////////////////////////////////////////
void NoeudSeqInst::ajouteInstruction(Noeud* instruction) {
  tabInst.push_back(instruction);
}

////////////////////////////////////////////////////////////////////////////////
// NoeudAffectation
////////////////////////////////////////////////////////////////////////////////

NoeudAffectation::NoeudAffectation(Noeud* variable, Noeud* expression) {
  this->variable=variable;
  this->expression=expression;
}

////////////////////////////////////////////////////////////////////////////////
int NoeudAffectation::getValeur() {
  int valeur = expression->getValeur(); // on évalue l'expression
  ((SymboleValue*)variable)->setValeur(valeur); // on affecte la variable
  return valeur; // par convention, une affectation a pour valeur la valeur affectée
}

////////////////////////////////////////////////////////////////////////////////
void NoeudAffectation::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Affectation" << endl;
  variable->afficher(indentation+1);   // on affiche variable et expression
  expression->afficher(indentation+1); // en augmentant l'indentation
}

////////////////////////////////////////////////////////////////////////////////
// NoeudOperateurBinaire
////////////////////////////////////////////////////////////////////////////////

NoeudOperateurBinaire::NoeudOperateurBinaire ( Symbole operateur,
                                               Noeud* operandeGauche,
                                               Noeud* operandeDroit) {
  this->operateur=operateur;
  this->operandeGauche=operandeGauche;
  this->operandeDroit=operandeDroit;
}
////////////////////////////////////////////////////////////////////////////////
 
void NoeudOperateurBinaire::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Operateur Binaire \"" << this->operateur.getChaine() << "\" applique a : " << endl;
  operandeGauche->afficher(indentation+1);  // on affiche fils gauche et fils droit
  operandeDroit->afficher(indentation+1);   // en augmentant l'indentation
}


////////////////////////////////////////////////////////////////////////////////
int NoeudOperateurBinaire::getValeur() { 
  int valeur=0;
  int og=operandeGauche->getValeur();
  int od=operandeDroit->getValeur();
  if      (this->operateur=="+") valeur = og+od; 
  else if (this->operateur=="-") valeur = og-od;
  else if (this->operateur=="*") valeur = og*od; 
  else if (this->operateur == "et") valeur = (og and od);
  else if (this->operateur == "ou") valeur = (og and od);
  else if (this->operateur == "==") valeur = (og == od);
  else if (this->operateur == "<") valeur = (og < od);
  else if (this->operateur == "<=") valeur = (og <= od);
  else if (this->operateur == ">") valeur = (og > od);
  else if (this->operateur == ">=") valeur = (og >= od);
  else if (this->operateur == "!=") valeur = (og != od);
  else  // this->operateur=="/"
  if (od!=0)
      valeur = og/od;
  else {
	 cout << "Erreur pendant l'interpretation : division par zero" << endl;
	 exit(0); // plus tard on levera une exception
  	}
  return valeur;
}

////////////////////////////////////////////////////////////////////////////////
// NoeudOperateurUnaire
////////////////////////////////////////////////////////////////////////////////

NoeudOperateurUnaire::NoeudOperateurUnaire (  Symbole operateur, Noeud* operande) {
  this->operateur=operateur;
  this->operande=operande;
}

////////////////////////////////////////////////////////////////////////////////
int NoeudOperateurUnaire::getValeur() {
  int valeur=0;
  int op=operande->getValeur();
  if      (this->operateur=="non") valeur = !op;
  else 
        valeur = - op;
  return valeur;
}

////////////////////////////////////////////////////////////////////////////////
void NoeudOperateurUnaire::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Operateur Unaire \"" << this->operateur.getChaine() << "\" applique a : " << endl;
  operande->afficher(indentation+1);  // on affiche fils gauche et fils droit
}


////////////////////////////////////////////////////////////////////////////////
// NoeudSi
////////////////////////////////////////////////////////////////////////////////

NoeudSi::NoeudSi(Noeud* expbool, Noeud* seqInst, Noeud* suivant) {
  this->expBool=expbool;
  this->seqInst=seqInst;
  this->siSuivant=suivant;
}

////////////////////////////////////////////////////////////////////////////////
int NoeudSi::getValeur() {
  int valeur = 1; // on évalue l'expression
  if (expBool->getValeur() == 1) seqInst->getValeur();
  if (siSuivant != NULL) siSuivant->getValeur();
//  ((SymboleValue*)variable)->setValeur(valeur); // on affecte la variable
  return valeur; // par convention, une affectation a pour valeur la valeur affectée
}

////////////////////////////////////////////////////////////////////////////////
void NoeudSi::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Si" << endl;
  expBool->afficher(indentation+1);   // on affiche variable et expression
  seqInst->afficher(indentation+1); // en augmentant l'indentation
  if (siSuivant != NULL)
          siSuivant->afficher(indentation+1); // en augmentant l'indentation
}

////////////////////////////////////////////////////////////////////////////////
// NoeudInstTq
////////////////////////////////////////////////////////////////////////////////

NoeudInstTq::NoeudInstTq(Noeud* condition, Noeud* seq) {
        this->condition=condition;
        this->seq=seq;
}

////////////////////////////////////////////////////////////////////////////////
int NoeudInstTq::getValeur() {
  int valeur=0;
  if (condition->getValeur())
          return seq->getValeur();
  return valeur; // par convention, resultat = valeur de la derniere instruction
}

////////////////////////////////////////////////////////////////////////////////
void NoeudInstTq::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Instruction TantQue:" << endl;
  condition->afficher(indentation+1);
  seq->afficher(indentation+1);
}

////////////////////////////////////////////////////////////////////////////////
// NoeudInstPour
////////////////////////////////////////////////////////////////////////////////

NoeudInstPour::NoeudInstPour(Noeud* aff1, Noeud* condition, Noeud* aff2, Noeud* seq) {
        this->condition = condition;
        this->aff1 = aff1;
        this->aff2 = aff2;
        this->seq = seq;
}

////////////////////////////////////////////////////////////////////////////////
int NoeudInstPour::getValeur() {
  int valeur=0;
  if (aff1->getValeur() && condition->getValeur() && aff2->getValeur())
          return seq->getValeur();
  return valeur; // par convention, resultat = valeur de la derniere instruction
}

////////////////////////////////////////////////////////////////////////////////
void NoeudInstPour::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Instruction Pour:" << endl;
  aff1->afficher(indentation+1);
  aff2->afficher(indentation+1);
  condition->afficher(indentation+1);
  seq->afficher(indentation+1);
}

////////////////////////////////////////////////////////////////////////////////
// NoeudInstRep
////////////////////////////////////////////////////////////////////////////////

NoeudInstRep::NoeudInstRep(Noeud* condition, Noeud* seq):NoeudInstTq(condition, seq) {

}

////////////////////////////////////////////////////////////////////////////////
int NoeudInstRep::getValeur() {
  int valeur=0;
  if (condition->getValeur())
          return seq->getValeur();
  return valeur; // par convention, resultat = valeur de la derniere instruction
}

////////////////////////////////////////////////////////////////////////////////
void NoeudInstRep::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Instruction Repeter" << endl;
  condition->afficher(indentation+1);
  seq->afficher(indentation+1);
}

////////////////////////////////////////////////////////////////////////////////
// NoeudInstLire
////////////////////////////////////////////////////////////////////////////////

NoeudInstLire::NoeudInstLire(Noeud* variable) {
        this->variable=variable;
}

////////////////////////////////////////////////////////////////////////////////
int NoeudInstLire::getValeur() {
  int valeur=0;

  return valeur; // par convention, resultat = valeur de la derniere instruction
}

////////////////////////////////////////////////////////////////////////////////
void NoeudInstLire::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - instruction Lire" << endl;
  variable->afficher(indentation+1);
}

////////////////////////////////////////////////////////////////////////////////
// NoeudInstEcrire
////////////////////////////////////////////////////////////////////////////////

NoeudInstEcrire::NoeudInstEcrire(Noeud* expression, Noeud* chaine) {
        this->expression = expression;
        this->chaine=chaine;
}

////////////////////////////////////////////////////////////////////////////////
int NoeudInstEcrire::getValeur() {
  int valeur=0;
  if(expression)
        return expression->getValeur();
  else
        return chaine->getValeur();
  return valeur; // par convention, resultat = valeur de la derniere instruction
}

////////////////////////////////////////////////////////////////////////////////
void NoeudInstEcrire::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Instruction Ecrire" << endl;
  if(expression)
        expression->afficher(indentation+1);
  else
        chaine->afficher(indentation+1);

}




